%%% util.erl - utility functions
%%%
%%% The MIT License
%%%
%%% Copyright (c) 2008 hellomatty@gmail.com
%%%
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
%%% of this software and associated documentation files (the "Software"), to deal
%%% in the Software without restriction, including without limitation the rights
%%% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
%%% copies of the Software, and to permit persons to whom the Software is
%%% furnished to do so, subject to the following conditions:
%%%
%%% The above copyright notice and this permission notice shall be included in
%%% all copies or substantial portions of the Software.
%%%
%%% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
%%% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
%%% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
%%% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
%%% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
%%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
%%% THE SOFTWARE.
%%%

-module(util).
-export([safe_pmap/2, safe_map/2, batch/2, unique/1]).

-include_lib("util.hrl").

safe_pmap(F, L) -> 
  S = self(),
  Pids = lists:map(fun(I) -> 
    spawn(fun() -> do_f(S, F, I) end)
  end, L),
  gather(Pids).

gather([H|T]) ->
    receive
        {H, {'EXIT', Reason}} ->
          ?D({pmap,child,exit,Reason}),
          gather(T);
	{H, Ret} ->
          [Ret|gather(T)]
    end;
gather([]) ->
    [].

do_f(Parent, F, I) ->
  Parent ! {self(), (catch F(I))}.

safe_map(F, [H|T]) ->
  case (catch F(H)) of
    {'EXIT',Reason} ->
      ?D({safe_map,child,exit,Reason}),
      safe_map(F,T);
    R ->
      [R|safe_map(F,T)]
  end;
safe_map(F, []) when is_function(F, 1) -> [].

batch(List, Size) ->
  batch(List, Size, [], []).
batch([], _Size, Batches, []) ->
  Batches;
batch([], _Size, Batches, Batch) ->
  [Batch|Batches];
batch([H|T], Size, Batches, Batch) when length(Batch) < Size ->
  batch(T, Size, Batches, [H|Batch]);
batch(List, Size, Batches, Batch) ->
  batch(List, Size, [Batch|Batches], []).
  
unique(List) ->
  unique(List, []).
unique([], UniqueList) ->
  UniqueList;
unique([H|Rest], UniqueList) ->
  case lists:member(H, UniqueList) of
    true ->
      unique(Rest, UniqueList);
    false ->
      unique(Rest, [H|UniqueList])
  end.
